package com.jichangxiu.framework.utils;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.jichangxiu.common.constant.Constants;
import com.jichangxiu.common.context.JcxContext;
import com.jichangxiu.common.entity.bo.DataSource;
import com.jichangxiu.common.properties.DruidProperties;
import com.jichangxiu.common.utils.RsaUtils;
import com.jichangxiu.framework.entity.bo.DynamicSource;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

@Slf4j
public class DynamicUtils {

    private static final Map<Object, Object> dynamicSourceMap = new HashMap<>();

    public static javax.sql.DataSource buildDataSource(String uniqueCode, Properties properties) throws Exception {
        AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
        atomikosDataSourceBean.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
        // 添加连接池限制
        atomikosDataSourceBean.setMaxPoolSize(50);
        atomikosDataSourceBean.setMinPoolSize(5);
        atomikosDataSourceBean.setBorrowConnectionTimeout(60);
        atomikosDataSourceBean.setUniqueResourceName(uniqueCode);
        atomikosDataSourceBean.setXaProperties(properties);
        return atomikosDataSourceBean;
    }

    public static void addDataSource(String code, javax.sql.DataSource dataSource) {
        DynamicSource dynamicSource = SpringUtil.getBean(DynamicSource.class);
        dynamicSourceMap.put(code, dataSource);
        dynamicSource.setTargetDataSources(dynamicSourceMap);
        dynamicSource.afterPropertiesSet();
        log.debug("【DynamicUtils】加载【" + code + "】数据源");
    }

    public static void addDataSource(DruidProperties druidProperties, String code, String url, String username, String password) throws Exception {
        Properties properties;
        try {
            properties = build(druidProperties, url, username, RsaUtils.decrypt(password));
        } catch (Exception exception) {
            properties = build(druidProperties, url, username, password);
        }
        javax.sql.DataSource dataSource = buildDataSource(code, properties);
        addDataSource(code, dataSource);
    }

    public static void addDataSource(DruidProperties druidProperties, DataSource dsInfo) throws Exception {
        Properties properties;
        try {
            properties = build(druidProperties, dsInfo.getUrl(), dsInfo.getUsername(), RsaUtils.decrypt(dsInfo.getPassword()));
        } catch (Exception exception) {
            properties = build(druidProperties, dsInfo.getUrl(), dsInfo.getUsername(), dsInfo.getPassword());
        }
        javax.sql.DataSource dataSource = buildDataSource(dsInfo.getCode(), properties);
        addDataSource(dsInfo.getCode(), dataSource);
    }

    public static boolean exist(String code) {
        return ObjectUtil.isNotEmpty(dynamicSourceMap.get(code));
    }

    public static void setDefaultSource() {
        resetSource();
        JcxContext.setSourceCode(Constants.DEFAULT_DATA_SOURCE);
    }

    public static void setCurrentTenantSource() {
        resetSource();
        String source = JcxContext.getTenantSource();
        if (StrUtil.isEmpty(source)) {
            source = Constants.DEFAULT_DATA_SOURCE;
        }
        JcxContext.setSourceCode(source);
    }

    public static void changeSource(String code) {
        resetSource();
        JcxContext.setSourceCode(code);
    }

    public static void resetSource() {
        JcxContext.clearSourceCode();
    }

    public static String currentSource() {
        String sourceCode = JcxContext.getSourceCode();
        if (StrUtil.isEmpty(sourceCode)) {
            sourceCode = Constants.DEFAULT_DATA_SOURCE;
            changeSource(sourceCode);
        }
        return sourceCode;
    }

    private static Properties build(DruidProperties druidProperties, String url, String username, String password) {
        Properties prop = new Properties();
        prop.put("url", url);
        prop.put("username", username);
        prop.put("password", password);
        prop.put("initialSize", druidProperties.getInitialSize());
        prop.put("minIdle", druidProperties.getMinIdle());
        prop.put("maxActive", druidProperties.getMaxActive());
        prop.put("maxWait", druidProperties.getMaxWait());
        prop.put("timeBetweenEvictionRunsMillis", druidProperties.getTimeBetweenEvictionRunsMillis());
        prop.put("minEvictableIdleTimeMillis", druidProperties.getMinEvictableIdleTimeMillis());
        prop.put("maxEvictableIdleTimeMillis", druidProperties.getMaxEvictableIdleTimeMillis());
        prop.put("validationQuery", druidProperties.getValidationQuery());
        prop.put("testWhileIdle", druidProperties.isTestWhileIdle());
        prop.put("testOnBorrow", druidProperties.isTestOnBorrow());
        prop.put("testOnReturn", druidProperties.isTestOnReturn());
        return prop;
    }

}
